package com.sys.core.init.mysql;

import com.sys.core.exception.ParsingClassException;
import com.sys.core.init.mysql.annotation.Column;
import com.sys.core.init.mysql.annotation.Id;
import com.sys.core.init.mysql.annotation.Table;
import com.sys.core.init.mysql.annotation.Entity;
import org.apache.commons.lang.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by 汤伟杰 on 2017/5/3.
 */
public class EntityClass {
    private Class<?> clazz;
    private List<ColumnClass> columnListMap = new ArrayList<ColumnClass>();

    private TableClass tableClass = new TableClass();



    public EntityClass(String className) throws Exception {
        try {
            System.out.println("解析类："+className);
            this.clazz = Class.forName(className);
            Entity entity = this.clazz.getAnnotation(Entity.class);
            if(entity!=null) {
                Table table = this.clazz.getAnnotation(Table.class);
                tableClass.setName(table.name());
                tableClass.setDescribe(table.describe());
                tableClass.setProperties(className);
                if("".equals(tableClass.getName())){
                    tableClass.setName(this.clazz.getName());
                }
                tableClass.setEngine(table.engine());

                for (Field field : clazz.getDeclaredFields()) {

                    Column annotation_column = field.getAnnotation(Column.class);
                    if (annotation_column != null) {
                        ColumnClass columnClass = new ColumnClass();
                        //columnTypeLengthDefaltComment
                        //column
                        if (!"".equals(annotation_column.name())) {
                            columnClass.setName(annotation_column.name());
                        } else {
                            columnClass.setName(field.getName());
                        }

                        //type length
                        if (String.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("varchar");
                            columnClass.setClasstype(String.class.getName());
                            columnClass.setLength(annotation_column.length());
                        } else if (Integer.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("int");
                            columnClass.setClasstype(Integer.class.getName());
                            if (annotation_column.length() > 11) {
                                columnClass.setLength(11);
                            } else {
                                columnClass.setLength(annotation_column.length());
                            }
                        } else if (BigDecimal.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("decimal");
                            columnClass.setClasstype(BigDecimal.class.getName());
                            if (annotation_column.length() <= 11) {
                                columnClass.setLength(annotation_column.length());
                                if(annotation_column.precision()==0){
                                    columnClass.setPrecision(2);
                                }else{
                                    columnClass.setPrecision(annotation_column.precision());
                                }

                            } else {
                                columnClass.setLength(11);
                                if(annotation_column.precision()==0){
                                    columnClass.setPrecision(2);
                                }else{
                                    columnClass.setPrecision(annotation_column.precision());
                                }
                            }
                        } else if (Double.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("double");
                            columnClass.setClasstype(Double.class.getName());
                            if (annotation_column.length() <= 11) {
                                columnClass.setLength(annotation_column.length());
                                if(annotation_column.precision()==0){
                                    columnClass.setPrecision(2);
                                }else{
                                    columnClass.setPrecision(annotation_column.precision());
                                }

                            } else {
                                columnClass.setLength(11);
                                if(annotation_column.precision()==0){
                                    columnClass.setPrecision(2);
                                }else{
                                    columnClass.setPrecision(annotation_column.precision());
                                }
                            }
                        } else if (Float.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("float");
                            columnClass.setClasstype(Float.class.getName());
                            if (annotation_column.length() <= 11) {
                                columnClass.setLength(annotation_column.length());
                                if(annotation_column.precision()==0){
                                    columnClass.setPrecision(2);
                                }else{
                                    columnClass.setPrecision(annotation_column.precision());
                                }

                            } else {
                                columnClass.setLength(11);
                                if(annotation_column.precision()==0){
                                    columnClass.setPrecision(2);
                                }else{
                                    columnClass.setPrecision(annotation_column.precision());
                                }
                            }
                        } else if (Date.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("datetime");
                            columnClass.setClasstype(Date.class.getName());
                            columnClass.setLength(null);
                        } else if (int.class.getName().equals(field.getType().getName())) {
                            //非法类型 int 不能用作创建表
                            throw new Exception("非法类型 int 不能用作创建表");
                        } else if (boolean.class.getName().equals(field.getType().getName())) {
                            columnClass.setType("tinyint");//从 0 到 255 的整型数据。存储大小为 1 字节。
                            columnClass.setLength(null);
                        } else {
                            //非法类型 field.getType().getClass() 不能用作创建表
                            throw new Exception("非法类型 " + field.getType() + " 不能用作创建表");
                        }
                        columnClass.setClasstypeSimple(columnClass.getClasstype().substring(columnClass.getClasstype().lastIndexOf(".")+1));
                        //Defalt
                        columnClass.setDefalt(annotation_column.defalt());
                        //comment
                        columnClass.setDescribe(annotation_column.describe());
                        //属性
                        columnClass.setProperties(field.getName());
                        //属性首字母大写
                        columnClass.setPropertiesUp(field.getName().substring(0,1).toUpperCase()+field.getName().substring(1));
                        //是否唯一
                        columnClass.setUnique(annotation_column.unique());
                        //是否可为空
                        columnClass.setNullable(annotation_column.nullable());
                        //判断是否主键
                        Id id = field.getAnnotation(Id.class);
                        if (id != null) {
                            tableClass.setPrimaryKey(columnClass.getName());
                            tableClass.setKeyProperties(columnClass.getProperties());
                            tableClass.setKeyType(columnClass.getClasstype());
                            tableClass.setKeyTypeSimple(columnClass.getClasstypeSimple());
                            tableClass.setKeyPropertiesUp(columnClass.getProperties().substring(0,1).toUpperCase()+columnClass.getProperties().substring(1));
                            columnClass.setNullable(false);
                            columnClass.setUnique(true);
                        }
                        columnClass.setInputType(annotation_column.inputType());
                        columnClass.setInputCode(annotation_column.inputCode());
                        columnListMap.add(columnClass);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ParsingClassException("解析类异常"+className+":"+e.getMessage());
        }
    }

    public List<ColumnClass> getColumn(){
       return columnListMap;

    }
    public TableClass getTable(){
        return tableClass;

    }

    public String create(){
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("CREATE TABLE `"+tableClass.getName()+"` (");
        stringBuffer.append("\n");
        for (int i = 0; i < columnListMap.size(); i++) {
            stringBuffer.append("  `"+columnListMap.get(i).getName()+"` "+columnListMap.get(i).getType());
            if (columnListMap.get(i).getLength()!=null) {
                stringBuffer.append("("+columnListMap.get(i).getLength());//
                if(columnListMap.get(i).getPrecision()!=0){
                    stringBuffer.append(","+columnListMap.get(i).getPrecision());
                }
                stringBuffer.append(")");
            }
            if(!"".equals(columnListMap.get(i).getDefalt())){
                String value =columnListMap.get(i).getDefalt().trim();
                if(value.contains("${")&&value.contains("}")){
                    value = value.substring(value.indexOf("${")+2, value.indexOf("}"));
                    stringBuffer.append(" DEFAULT "+value);
                }else{
                    stringBuffer.append(" DEFAULT '"+value+"'");
                }

            }else if(columnListMap.get(i).isNullable()){
                stringBuffer.append(" DEFAULT NULL ");
            }else{
                stringBuffer.append(" NOT NULL ");
            }

            if(!"".equals(columnListMap.get(i).getDescribe())){
                stringBuffer.append(" COMMENT '"+columnListMap.get(i).getDescribe()+"'");
            }
            if(i!=columnListMap.size()-1){
                stringBuffer.append(",");
            }
            stringBuffer.append("\n");
        }

        if(tableClass.getPrimaryKey()!=null){
            stringBuffer.append(",  PRIMARY KEY (`"+tableClass.getPrimaryKey()+"`)");
        }
        stringBuffer.append("\n");
        stringBuffer.append(")ENGINE="+tableClass.getEngine()+" DEFAULT CHARSET=utf8 ");
        if(!"".equals(tableClass.getDescribe())){
            stringBuffer.append(" COMMENT '"+tableClass.getDescribe()+"';");
        }else{
            stringBuffer.append(";");
        }

        return stringBuffer.toString().trim();
    }

    public List<String> update(List<String> columnList){
        List<String> updateList = new ArrayList<String>();

        for (int i = 0; i < columnListMap.size(); i++) {
            if(!columnList.contains(columnListMap.get(i).getName())){
                updateList.add(getUpdateSql(columnListMap.get(i)));
            }

        }

        //ALTER TABLE chezhujie.czj_city ADD column_5 VARCHAR(1) NULL;
        return updateList;
    }

    private String getUpdateSql(ColumnClass columnClass) {
        String string = "ALTER TABLE "+this.getTable().getName()+" ADD "+columnClass.getName()+" "+columnClass.getType();
        //(11) 或者(10,2)
        if(columnClass.getLength() ==null||columnClass.getLength()==0){
            string+=" ";
        }else{
            if("decimal".equalsIgnoreCase(columnClass.getType())){
                string+=" ("+columnClass.getLength()+","+columnClass.getPrecision()+") ";
            }else{
                string+=" ("+columnClass.getLength()+") ";
            }

        }
        //DEFAULT NULL
        if(StringUtils.isBlank(columnClass.getDefalt())){
            string+=" DEFAULT NULL";
        }else{
            string+=" DEFAULT '"+columnClass.getDefalt()+"'";
        }
        //comment ''
        if(columnClass.getDescribe()!=null){
            string+=" COMMENT '"+columnClass.getDescribe()+"'";
        }

        return string;
    }

    private String getUpdateSql(String tablename,String columnname,String type,Integer length,Integer precision,String defalt){
        String string = "ALTER TABLE "+tablename+" ADD "+columnname+" "+type;
        if(length ==null||length==0){
            string+=" ";
        }else{
            if("decimal".equalsIgnoreCase(type)){
                string+=" ("+length+","+precision+") ";
            }else{
                string+=" ("+length+") ";
            }

        }
        if(defalt==null){
            string+="NULL";
        }else{
            string+=defalt;
        }

        return string;
    }


}
